import { lastValueFrom, Observable, of,catchError,map, switchMap} from 'rxjs'
import { Lang} from 'c3-util'
import { SoaResponseInfo } from './SoaResponseInfo'
import {SoaService} from './SoaService'
import { DbService } from './MockDbService'
import { IRpcMethod } from '../rpcServer/IRpcMethod'
import {JSJaCConsoleLogger}  from '../jsjac/'

// SPDN的一些服务
const SPDN_Service=[
    'C3_CheckServer', 'C3_GetSpdnUrl', 'C3_GetSpdnUrlByTerm', 'C3_ServiceCheck', 
    'C3_ImrCheck', 'C3_GetEccParams', 'C3_GetEccCompanyParams', 'C3Agent_GetLoginPageInfo', 
    'C3Agent_Login_Sso', 'C3_GetStaffLoginCode', 'C3_StaffLogin', 'Agent_IpLimit',
     'C3_GetServerInfo', 'C3_GetVersion', 'C3_UpdateVersionLog'
]

export  class SoaUtil {
    private static soaService=new SoaService(['http://192.168.0.17/c3iservuc/services/v1/T/common/'])
    private static companyId:string='27_84'
    private static staffId:string='398889755710169088'
    private static log=new JSJaCConsoleLogger()


    /**
     * 给RpcServer注册的方法
     * @returns 需要对外注册的方法
     */
    public static getRegisterRpcMethod():Array<IRpcMethod>{
        const callC3ImrCheck:IRpcMethod={
            methodName:'soa.callC3ImrCheck',
            isPublic:true,
            handle:params =>{
                if(params.length<2){
                    this.log.warn('soa.callC3ImrCheck,调用服务的参数不对,至少要两个参数')
                    return SoaResponseInfo.createResponse('callC3ImrCheck',-21,'调用服务的参数不对,至少要两个参数').getOrialData()
                }
                return this.handleObservableToPromise(SoaUtil.callC3ImrCheck(params[0],params[1]))
            }
        }
        const c3CheckServerTest:IRpcMethod={
            methodName:'soa.c3CheckServerTest',
            isPublic:true,
            handle:params =>{
                if(params.length<2){
                    this.log.warn('soa.c3CheckServerTest,调用服务的参数不对,至少要两个参数')
                    return SoaResponseInfo.createResponse('c3CheckServerTest',-21,'调用服务的参数不对,至少要两个参数').getOrialData()
                }
                return this.handleObservableToPromise(SoaUtil.c3CheckServerTest(params[0],params[1]))
            }
        }
        const callService:IRpcMethod={
            methodName:'soa.callService',
            isPublic:true,
            handle:params =>{
                if(params.length<2){
                    this.log.warn('soa.callService,调用服务的参数不对,至少要两个参数')
                    return SoaResponseInfo.createResponse('callService',-21,'调用服务的参数不对,至少要两个参数').getOrialData()
                }
                return this.handleObservableToPromise(SoaUtil.callService(params[0],params[1]))
            }
        }
      return [callC3ImrCheck,c3CheckServerTest,callService]
    }

    /**
     * 设置当前的spdn地址,如果spdn地址不在spdn列表，就加入并且设置为当前spdn地址，
     * 如果已经存在就设置当前spdn地址 
     * @param spdnUrl spdn地址
     */
    public static setCurrSpdnUrl(spdnUrl:string):boolean{
        return this.soaService.changeCurrSpdnUrl(spdnUrl)
    }

    /**
     * 根据termNo,验证注册号是否存在，是否与设置网匹配
     * @param termNo 
     * @param clientType 
     * @returns 
     */
    public static callC3ImrCheck(termNo:string,clientType:string):Observable<SoaResponseInfo>{
        //TODO 调用数据库模块getSpdnByTerm(termNo)
        const spdnServerConfigs=[{
            url:'http://192.168.0.17/c3iservuc/services/v1/T/common/',
            netFlag:'0'
        }]
        this.soaService=new SoaService(['http://192.168.0.17/c3iservuc/services/v1/T/common/'])
        const c3ImrCheck$=this.soaService.callCommonService('C3_ImrCheck',{
            term_serial_no:termNo,
            client_type:clientType
        }).pipe(
            switchMap(respInfo=>{
                if(!respInfo.success()){
                    return of(respInfo)
                }
                const termNetFlagOption=respInfo.getFirstTableColumnValue('net_flag')
                const  errRespInfo=new SoaResponseInfo(respInfo.getServiceName())
                if(termNetFlagOption.isEmpty()){
                    errRespInfo.setResultCode(-4)
                    errRespInfo.setResultMessage('无法获取终端配置信息')
                    return of(errRespInfo)
                }
                //判断终端网络和spdn网络是否一样
                const currSnpdUrl=this.soaService.getCurrSpdnUrl()
                let isSameNetFlagTermAndSpdn=false
                spdnServerConfigs.forEach(spdnConfig=>{
                    if(spdnConfig.url===currSnpdUrl && spdnConfig.netFlag==termNetFlagOption.get()){
                        isSameNetFlagTermAndSpdn=true
                    }
                })
                if(isSameNetFlagTermAndSpdn){
                    //TODO 调用db.saveTermInfo()，保存记录到数据库
                    DbService.saveTermInfo(respInfo)
                    return this.callC3_GetSpdnUrlByTerm(respInfo,termNo,clientType)
                }
                errRespInfo.setResultCode(-5)
                errRespInfo.setResultMessage('注册号网络类型(外网)不匹配当前服务的网络(内网)')
                return of(errRespInfo)
            })
        )
        return c3ImrCheck$
    }
    /**
     * 调用该终端最新的spdn服务，并且保存最spdn列表到db中
     * @param c3ImrCheckResponse c3ImrCheck服务成功返回结果
     * @param termNo 
     * @param clientType 
     * @returns 
     */
    private static callC3_GetSpdnUrlByTerm(c3ImrCheckResponse:SoaResponseInfo,termNo:string,clientType:string):Observable<SoaResponseInfo>{
        return this.soaService.callCommonService('C3_GetSpdnUrlByTerm',{
            term_serial_no:termNo,
            client_type:clientType
        }).pipe(
            switchMap(spdnUrlByTermrespInfo=>{
                if(spdnUrlByTermrespInfo.success()){
                    //TODO 把结果保存到db.saveSpdnUrl()
                    DbService.saveSpdnUrl(spdnUrlByTermrespInfo)
                }
                return of(c3ImrCheckResponse)
            })
        )

    }
    /**
     *  使用ip,port作为commonUlr,调用服务C3_checkServer验证地址是否正确
     * @param ip 测试的IP地址
     * @param port  端口
     * @returns 
     */
    public static c3CheckServerTest(ip:string,port:string):Observable<SoaResponseInfo>{
        const spdnUrl='http://'+ip+':'+port+'/c3iservuc/services/v1/T/common/'
        const testSoaService=new SoaService([spdnUrl])
        const commonService$=testSoaService.callCommonService('C3_CheckServer',{
            server_ip:ip,
            server_port:port,
            server_type:'SPDN'
        })
        return commonService$
    }
    /**
     * 调用服务
     * @param serviceName 服务名
     * @param inputJson 输入参数'{"column_name1":"value1","column_name2":"value2"}'
     * @returns 
     */
    public static callService(serviceName:string,inputBody:object):Observable<SoaResponseInfo>{
        if(Lang.isEmpty(this.soaService.getCurrStaffUrl())) {
            this.log.debug('init staff')
            this.soaService.setStaffUrls(['http://192.168.0.17/c3iservuc/services/v1/T/staff/'])

        }
        if(Lang.isEmpty(inputBody)){
            let errResponse=new SoaResponseInfo(serviceName)
            errResponse.setResultCode(-19)
            errResponse.setResultMessage('inputParam is empty')
            return of(errResponse)
        }
        //SPDN服务
        if(SPDN_Service.find(spdnService=>spdnService===serviceName)){
            const spdnService$=this.soaService.callCommonService(serviceName,inputBody)
            return spdnService$
        }
        const staffService$=this.soaService.callStaffService(this.companyId,this.staffId,serviceName,inputBody)
        return staffService$
    }

    /**
     * 把observable改为promise
     * @param responseObservable 调用服务返回结果
     * @returns 
     */
    private static handleObservableToPromise(responseObservable:Observable<SoaResponseInfo>):Promise<object>{
        let service$=responseObservable.pipe(
            catchError(err=>{
            let errResponse=new SoaResponseInfo('unknow service')
            errResponse.setResultCode(-18)
            errResponse.setResultMessage('call error:'+err.message)
            return of(errResponse)
            }),
            map(soaResp=>soaResp.getOrialData())
        )
        return lastValueFrom(service$)
    }
}